﻿using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using System.IO;

/*********************************************************
 * 
 * programmer:		patrick.woolhoo@gmail.com
 * svn:				http://woolhoo-net.googlecode.com/svn/trunk/wnet/
 * class:			Uploader
 * desc:			实现文件上传功能，可以在appsettings中进行必要设置
 * 
 * *******************************************************/

namespace Patrick.Custom {
	/// <summary>
	/// 上传指定的文件，返回已上传的文件路径信息。
	/// </summary>
	public class Uploader {
		public static NameValueCollection Upload(HttpFileCollection Files) {
			// 上传文件，必须过滤文件类型，在Web.Config中有AppSettings["UploadTypes"]
			NameValueCollection RetValue = new NameValueCollection();
			if (Files.Count > 0) {
				List<string> AllowedTypes = new List<string>();
				List<string> Settings = new List<string>(ConfigurationManager.AppSettings.AllKeys);
				StringBuilder DestPath = new StringBuilder();
				string[] InputNames = Files.AllKeys;
				StringBuilder SavedFileName = new StringBuilder();
				StringBuilder FrontName = new StringBuilder();
				StringBuilder Ext = new StringBuilder();

				if (Settings.Contains("UploadTypes")) {
					AllowedTypes = new List<string>(ConfigurationManager.AppSettings["UploadTypes"].Split(new char[] { ',' }));
				}

				if (Settings.Contains("UploadPath")) DestPath.Append(ConfigurationManager.AppSettings["UploadPath"]);
				else DestPath.Append("~/Uploaded/");
				if (!DestPath.ToString().EndsWith("/")) DestPath.Append("/");

				string ext = "";
				for (int i = 0; i < Files.Count; i++) {
					if (Files[i].ContentLength > 0) {
						if (Path.HasExtension(Files[i].FileName)) ext = Path.GetExtension(Files[i].FileName).ToLower().Substring(1);
						if (AllowedTypes.Contains(ext)) {
							// 保存文件
							int Repeater = 0;
							FrontName.Length = 0;
							FrontName.Append(Path.GetFileNameWithoutExtension(Files[i].FileName));
							Ext.Length = 0;
							Ext.Append(Path.GetExtension(Files[i].FileName));
							SavedFileName.Length = 0;
							SavedFileName.Append(FrontName.ToString() + Ext.ToString());
							while (File.Exists(HttpContext.Current.Server.MapPath(DestPath.ToString()) + SavedFileName.ToString())) {
								SavedFileName.Length = 0;
								SavedFileName.Append(FrontName.ToString());
								SavedFileName.Append("(" + (++Repeater).ToString() + ")");
								SavedFileName.Append(Ext.ToString());
							}
							// 建立文件夹
							if (!Directory.Exists(HttpContext.Current.Server.MapPath(DestPath.ToString()))) {
								try {
									Directory.CreateDirectory(HttpContext.Current.Server.MapPath(DestPath.ToString()));
								} catch (Exception e) {
									throw new ApplicationException("建立上传文件夹失败！", e);
								} finally {
									DeleteFiles(RetValue);
									RetValue.Clear();
								}
							}
							Files[i].SaveAs(HttpContext.Current.Server.MapPath(DestPath.ToString()) + SavedFileName.ToString());
							RetValue.Add(InputNames[i], DestPath.ToString() + SavedFileName.ToString());
						} else {
							// 出错则删除刚才已经保存的文件
							DeleteFiles(RetValue);
							return null;
						}
					}
				}
			}
			return RetValue;
		}


		/// <summary>
		/// 上传提交的文件，返回已上传的文件路径信息。
		/// 如果文件格式不允许上传会引发 InvalidOperationExecption
		/// 如果建立文件上传路径出错会引发 ApplicationException
		/// </summary>
		/// <returns></returns>
		public static NameValueCollection Upload() {
			// 上传文件，必须过滤文件类型，在Web.Config中有AppSettings["UploadTypes"]
			NameValueCollection RetValue = null;
			try {
				RetValue = Upload(HttpContext.Current.Request.Files);
			} catch (Exception e) {
				throw e;
			}
			return RetValue;
		}



		/// <summary>
		/// 删除指定虚拟目录中的文件
		/// </summary>
		/// <param name="Files"></param>
		public static void DeleteFiles(NameValueCollection Files) {
			foreach (string key in Files.AllKeys) {
				try {
					File.Delete(HttpContext.Current.Server.MapPath(Files[key]));
				} catch {
					return;
				}
			}
		}
	}
}